package weibo;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;

import javax.microedition.io.HttpConnection;

import net.rim.blackberry.api.browser.URLEncodedPostData;
import net.rim.device.api.io.http.HttpProtocolConstants;
import net.rim.device.api.io.transport.ConnectionDescriptor;
import net.rim.device.api.io.transport.ConnectionFactory;
import net.rim.device.cldc.io.ssl.TLSIOException;
import weibo.http.ImageItem;
import weibo.http.Response;
import weibo.model.Paging;
import weibo.model.PostParameter;
import weibo.model.WeiboException;
import code.Function;
import code.StringUtility;
import ctrl.MyConnectionFactory;

public class Weibo
{
	private HttpConnection client=null;
	private String token;

	public Weibo() {}
	
	public void setToken(String token) {this.token = token;}
	
	public Response get(String url) throws WeiboException {return get(url, new PostParameter[0]);}
	
	public Response get(String url, PostParameter[] params)	throws WeiboException
	{
		if (params!=null && params.length > 0)
		{
			String encodedParams = encodeParameters(params);
			if(url.indexOf("?")==-1)
			{
				url += "?" + encodedParams;
			} else {
				url += "&" + encodedParams;
			}
		}

		return httpRequest(url);
	}
	
	public Response get(String url, PostParameter[] params, Paging paging) throws WeiboException
	{
		if (paging!=null)
		{
			Vector pagingParams=new Vector(4);
			
			if(paging.getMaxId()!=-1) {pagingParams.addElement(new PostParameter("max_id", String.valueOf(paging.getMaxId())));}
			if(paging.getSinceId()!=-1) {pagingParams.addElement(new PostParameter("since_id", String.valueOf(paging.getSinceId())));}
			if(paging.getPage()!=-1) {pagingParams.addElement(new PostParameter("page", String.valueOf(paging.getPage())));}
			if(paging.getCount()!=-1) 
			{
				if (url.indexOf("search")!=-1)
				{
					pagingParams.addElement(new PostParameter("rpp", String.valueOf(paging.getCount())));
				} else {
					pagingParams.addElement(new PostParameter("count", String.valueOf(paging.getCount())));
				}
			}
			
			PostParameter[] newparams = null;
			PostParameter[] arrayPagingParams=new PostParameter[pagingParams.size()];
			System.arraycopy(pagingParams, 0, arrayPagingParams, 0, pagingParams.size());
			if (params!=null)
			{
				newparams = new PostParameter[params.length+pagingParams.size()];
				System.arraycopy(params, 0, newparams, 0, params.length);
				System.arraycopy(arrayPagingParams, 0, newparams, params.length, pagingParams.size());
			} else {
				if (arrayPagingParams.length!=0)
				{
					String encodedParams = encodeParameters(arrayPagingParams);
					if (url.indexOf("?")!=-1)
					{
						url += "&" + encodedParams;
					} else {
						url += "?" + encodedParams;
					}
				}
			}
			return get(url, newparams);
		} else {
			return get(url, params);
		}
	}

	/**
	 * 支持multipart方式上传图片
	*/
	public Response multPartURL(String url, PostParameter[] params, ImageItem item) throws WeiboException
	{
		URLEncodedPostData postData=new URLEncodedPostData("UTF-8", false);
		
		for(int i=0; i<params.length; i++)
		{
			postData.append(params[i].getName(), params[i].getValue());
		}
		
		return httpRequest(url, params, item);
	}
/*
	public Response multPartURL(String fileParamName, String url,
			PostParameter[] params, File file, boolean authenticated)
			throws WeiboException {
		PostMethod postMethod = new PostMethod(url);
		try {
			Part[] parts = null;
			if (params == null) {
				parts = new Part[1];
			} else {
				parts = new Part[params.length + 1];
			}
			if (params != null) {
				int i = 0;
				for (PostParameter entry : params) {
					parts[i++] = new StringPart(entry.getName(),
							(String) entry.getValue());
				}
			}
			FilePart filePart = new FilePart(fileParamName, file.getName(),
					file, new MimetypesFileTypeMap().getContentType(file),
					"UTF-8");
			filePart.setTransferEncoding("binary");
			parts[parts.length - 1] = filePart;

			postMethod.setRequestEntity(new MultipartRequestEntity(parts,
					postMethod.getParams()));
			return httpRequest(postMethod);
		} catch (Exception ex) {
			throw new WeiboException(ex.getMessage(), ex, -1);
		}
	}
*/

	/**
	 * 上传带图片的微博
	 * @param url 微博api地址
	 * @param params 微博文字
	 * @param imageData 图片
	 * @return 返回json格式的status
	 */
	private Response httpRequest(String url, PostParameter[] params, ImageItem imageData)
	{
		String string="";
		String twoHyphens = "--";  
	    String boundary = "****************256176b82bde4478";    // what_hell_is_that  
	    String lineEnd = "\r\n";
	    
	    OutputStream output=null;
	    InputStream input=null;
	    
		MyConnectionFactory factory=new MyConnectionFactory();
		factory.setConnectionMode(ConnectionFactory.ACCESS_READ_WRITE);
		ConnectionDescriptor descriptor=factory.getConnection(url);
		
        if(descriptor==null) {Function.errorDialog("Open connection failed!");}
        
        client=(HttpConnection) descriptor.getConnection();

		try
		{
			client.setRequestMethod(HttpConnection.POST);
			client.setRequestProperty(HttpProtocolConstants.HEADER_CONNECTION, HttpProtocolConstants.HEADER_KEEP_ALIVE);
			client.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE, HttpProtocolConstants.CONTENT_TYPE_MULTIPART_FORM_DATA + "; boundary="+boundary);

			URLEncodedPostData lengthData=new URLEncodedPostData("UTF-8", false);
			for(int i=0; i<params.length; i++)
    		{
    			lengthData.append(params[i].getName(), params[i].getValue());
    		}
			int length=lengthData.getBytes().length;
			length+=imageData.getContent().length;
			
			client.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, Integer.toString(length));
			
			client.setRequestProperty(HttpProtocolConstants.HEADER_AUTHORIZATION, "OAuth2 " + token);
			client.setRequestProperty("API-RemoteIP", Function.getIP());
		} catch (TLSIOException e)
		{
			Function.errorDialog("Setup client property error.\n\nDetail: " + e.toString());
		} catch (OutOfMemoryError e) 
		{
			Function.errorDialog("Setup client property error.\n\nDetail: " + e.toString());
			System.gc();
		} catch (IOException e) {
			Function.errorDialog("Setup client property error.\n\nDetail: " + e.toString());
		}

		try
		{
			output=client.openOutputStream();
			
			//insert IMAGE
			StringBuffer imageBuffer = new StringBuffer();  
			imageBuffer.append(twoHyphens + boundary + lineEnd);  
			imageBuffer.append("Content-Disposition: form-data; name=\"pic\"; filename=\"" + imageData.getFilename() + "\"" + lineEnd);  
			imageBuffer.append("Content-Type: " + imageData.getContentType() + lineEnd);  
			imageBuffer.append(lineEnd);
            
            output.write(imageBuffer.toString().getBytes());  
            output.write(imageData.getContent(), 0, imageData.getContent().length);  
            output.write(lineEnd.getBytes());  
		} catch (TLSIOException e)
		{
			Function.errorDialog("Insert image error.\n\nDetail: " + e.toString());
		} catch (OutOfMemoryError e) 
		{
			Function.errorDialog("Insert image error.\n\nDetail: " + e.toString());
			System.gc();
		} catch (IOException e) {
			Function.errorDialog("Insert image error.\n\nDetail: " + e.toString());
		}
		
		try
		{
            //insert TEXT
            StringBuffer statusBuffer=new StringBuffer();
    		URLEncodedPostData postData=new URLEncodedPostData("UTF-8", false);
    		
    		for(int i=0; i<params.length; i++)
    		{
    			postData.append(params[i].getName(), params[i].getValue());
    			
    			statusBuffer.append(twoHyphens + boundary + lineEnd);  
                String[] temp=StringUtility.split(postData.toString(), "=");
                statusBuffer.append("Content-Disposition: form-data; name=\"" + temp[0] + "\"" + lineEnd);  
                statusBuffer.append(lineEnd);  
                statusBuffer.append(temp[1] + lineEnd);  
    		}
            output.write(statusBuffer.toString().getBytes());
            output.write((twoHyphens+boundary+twoHyphens+lineEnd).getBytes());
		} catch (TLSIOException e)
		{
			Function.errorDialog("Insert text error.\n\nDetail: " + e.toString());
		} catch (OutOfMemoryError e) 
		{
			Function.errorDialog("Insert text error.\n\nDetail: " + e.toString());
			System.gc();
		} catch (IOException e) {
			Function.errorDialog("Insert text error.\n\nDetail: " + e.toString());
		}
		
		try
		{
            output.flush();
            output.close();
            //Thread.yield();
		} catch (TLSIOException e)
		{
			Function.errorDialog("Flush data error.\n\nDetail: " + e.toString());
		} catch (OutOfMemoryError e) 
		{
			Function.errorDialog("Flush data error.\n\nDetail: " + e.toString());
			System.gc();
		} catch (IOException e) {
			Function.errorDialog("Flush data error.\n\nDetail: " + e.toString());
		}
		
		try
		{
			if(client.getResponseCode()==HttpConnection.HTTP_OK)
			{
				input=client.openInputStream();
		        string=Function.readStream(input);
			} else {
				Function.errorDialog("Error\n\nResponse Code: " + client.getResponseCode());
			}
		} catch (TLSIOException e)
		{
			Function.errorDialog("Get return status error.\n\nDetail: " + e.toString());
		} catch (OutOfMemoryError e) 
		{
			Function.errorDialog("Get return status error.\n\nDetail: " + e.toString());
			System.gc();
		} catch (IOException e) {
			Function.errorDialog("Get return status error.\n\nDetail: " + e.toString());
		} finally {
			if(input!=null) {try {input.close();} catch (Exception e) {}}
        	if(client!=null) {try {client.close();} catch (Exception e) {}}  
        	if(output!=null) {try {output.close();} catch (Exception e) {}}
		}
		
		Response response = new Response();
		response.setResponseAsString(string);

		return response;
	}
	
	private Response httpRequest(String url) throws WeiboException
	{
		return httpRequest(url, null, true);
	}
	
	private Response httpRequest(String url, URLEncodedPostData postData, boolean WithTokenHeader) throws WeiboException
	{
		String string="";
		
		MyConnectionFactory factory=new MyConnectionFactory();
		factory.setConnectionMode(ConnectionFactory.ACCESS_READ_WRITE);
		ConnectionDescriptor descriptor=factory.getConnection(url);
		
        if(descriptor==null) {throw new WeiboException("Open connection failed!");}
        
        client=(HttpConnection) descriptor.getConnection();

		if(postData!=null)
		{
			if(WithTokenHeader)
			{
				if(token == null) {throw new WeiboException("Oauth2 token is not set!");}
					
				try {
					client.setRequestProperty("Authorization", "OAuth2 " + token);
					client.setRequestProperty("API-RemoteIP", Function.getIP());
				} catch (IOException e) {}
			}
			
			try {
				OutputStream outputStream=null;
				client.setRequestMethod(HttpConnection.POST);
                client.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE, postData.getContentType());
                byte [] postBytes = postData.getBytes();
                client.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, Integer.toString(postBytes.length));
                outputStream = client.openOutputStream();
                outputStream.write(postBytes);
                outputStream.flush();
                outputStream.close();
                outputStream = null;

                InputStream inputStream=null;
				inputStream=client.openInputStream();
		        string=Function.readStream(inputStream);
			} catch (Exception e) {throw new WeiboException(e.toString());}
		} else {
			if(WithTokenHeader)
			{
				if(token == null) {throw new IllegalStateException("Oauth2 token is not set!");}
				
				try {
					client.setRequestProperty("Authorization", "OAuth2 " + token);
					client.setRequestProperty("API-RemoteIP", Function.getIP());
				} catch (IOException e) {}
			}

			InputStream inputStream=null;
			try {
				client.setRequestMethod(HttpConnection.GET);
				inputStream=client.openInputStream();
		        string=Function.readStream(inputStream);
			} catch (IOException e)
			{
				throw new WeiboException(e.toString());
			}  finally {
	        	if(inputStream!=null) {try {inputStream.close();} catch (Exception e2) {}}
	        	if(client!=null) {try {client.close();} catch (Exception e2) {}}
	        }
		}
		
        Response response = new Response();
		response.setResponseAsString(string);

		return response;
	}
	
	public Response post(String url, PostParameter[] params) throws WeiboException
	{
		return post(url, params, false);

	}

	public Response post(String url, PostParameter[] params, boolean WithTokenHeader) throws WeiboException
	{
		URLEncodedPostData postData=new URLEncodedPostData("UTF-8", false);
		
		for(int i=0; i<params.length; i++)
		{
			postData.append(params[i].getName(), params[i].getValue());
		}
		
		//if(!WithTokenHeader)
		//{
		//	return httpRequest(url);
		//} else {
			return httpRequest(url, postData, WithTokenHeader);
		//}
	}

	public static String encodeParameters(PostParameter[] postParams) 
	{
		StringBuffer buf = new StringBuffer();
		for (int j = 0; j < postParams.length; j++)
		{
			if (j!=0) {buf.append("&");}
			
			try {
				buf.append(new String(postParams[j].getName().getBytes(), "UTF-8"))
				.append("=").append(new String(postParams[j].getValue().getBytes(), "UTF-8"));
			} catch (Exception e) {}
		}
		return buf.toString();
	}
}